package com.spartez.farhorizons.client;

import java.util.Collection;
import java.util.HashMap;

import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.gwtext.client.core.Margins;
import com.gwtext.client.core.RegionPosition;
import com.gwtext.client.util.Format;
import com.gwtext.client.widgets.Panel;
import com.gwtext.client.widgets.form.Checkbox;
import com.gwtext.client.widgets.form.event.CheckboxListenerAdapter;
import com.gwtext.client.widgets.layout.BorderLayout;
import com.gwtext.client.widgets.layout.BorderLayoutData;
import com.gwtext.client.widgets.layout.FitLayout;
import com.gwtext.client.widgets.layout.HorizontalLayout;
import com.spartez.farhorizons.client.data.ISystemDescr;
import com.spartez.farhorizons.client.map.DistanceDisplayComponent;
import com.spartez.farhorizons.client.map.SystemComponent;

public class MapPanel extends Panel implements DataService.StarListListener {
	HTMLPanel content = new HTMLPanel("<big><code>Press System Info in top right corner & paste the list of stars (not the map)</code></big>");
	final ScrollPanel scroll;
	private boolean compact;
	private Collection<? extends ISystemDescr> lastDescriptions;
	
	public MapPanel() {
        setLayout(new FitLayout());
        Panel container = new Panel();
        container.setLayout(new BorderLayout());
        add(container);
        
        scroll = new ScrollPanel(content);
		container.add(scroll, new BorderLayoutData(RegionPosition.CENTER));
        Panel buttons = new Panel();
        BorderLayoutData buttonsData = new BorderLayoutData(RegionPosition.SOUTH);  
        buttonsData.setMargins(new Margins(3, 3, 3, 3));  
        buttons.setLayout(new HorizontalLayout(8));
        
        final Checkbox compactCb = new Checkbox("Compact");
        compactCb.addListener(new CheckboxListenerAdapter() {
			public void onCheck(Checkbox field, boolean checked) {
				compact = checked;
				if (lastDescriptions != null) {
					starListChanged(lastDescriptions);
				}
			}
        });
		buttons.add(compactCb);
		buttons.add(new DistanceDisplayComponent());
        buttons.setHeight("auto");
        container.add(buttons, buttonsData);
        
        setBodyStyle("background-color:C3D9FF");
        setBodyStyle("whiteSpace:nowrap");
        buttons.setBodyStyle("background-color:C3D9FF");
		
        FarHorizons.dataService.registerStarListListener(this);
 	}

	private static class XY {
		final int x;
		final int y;
		final int hashcode;
		
		XY(int x, int y) {
			this.x = x;
			this.y = y;
			this.hashcode = x + (y << 16);
		}

		@Override
		public boolean equals(Object obj) {
			if (! (obj instanceof XY)) {
				return false;
			}
			XY other = (XY) obj;
			return other.x == x && other.y == y;
		}

		@Override
		public int hashCode() {
			return hashcode;
		}
		
		
	}

	public void starListChanged(Collection<? extends ISystemDescr> systems) {
		lastDescriptions = systems;
		HashMap<XY, ISystemDescr> index = new HashMap<XY, ISystemDescr>(systems.size());
		int maxX = 0;
		int maxY = 0;
		for (ISystemDescr sd : systems) {
			index.put(new XY(sd.getX(), sd.getY()), sd);
			if (maxX < sd.getX()) {
				maxX = sd.getX();
			}
			if (maxY < sd.getY()) {
				maxY = sd.getY();
			}
		}
		
		StringBuilder sb = new StringBuilder("<code>");
		for (int y = maxY; y >= 0; y--) {
			generateRow(sb, y, maxX, index);
		}
		sb.append("&nbsp;Y&nbsp;-");
		for (int i = 0; i <= maxX; i++) {
			sb.append(compact ? "---" : "------");
		}
	
		sb.append("<br>");
		sb.append("&nbsp;&nbsp;X");
		for (int i = 0; i <= maxX; i++) {
			sb.append(Format.leftPad(String.valueOf(i), compact ? 2 : 5).replace(" ", "&nbsp;"));
			sb.append("&nbsp;");
		}
		sb.append("<br>");
		
		
		sb.append("</code>");
		scroll.remove(content);
		content = new HTMLPanel(sb.toString());
		scroll.add(content);
		doLayout();
		assignLabels(index);
	}
	
	private void generateRow(StringBuilder sb, int y, int maxX,
			HashMap<XY, ISystemDescr> index) {
		if (!compact) {
			sb.append("&nbsp;&nbsp;&nbsp;");
			sb.append('-');
		
			for (int i = 0; i <= maxX; i++) {
				sb.append("------");
			}
			sb.append("<br>");
		}
		
		sb.append("&nbsp;&nbsp;&nbsp;|");
		for (int x = 0; x <= maxX; x++) {
			final XY idx = new XY(x, y);
			final ISystemDescr sd = index.get(idx);
			if (sd == null) {
				sb.append(compact ? "&nbsp;&nbsp;&nbsp;" : "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|");
			} else {
				sb.append("<span id=\"zcoord_").append(x).append("_").append(y).append("\">");
				sb.append(formatCell(String.valueOf(sd.getZ()), compact));
				sb.append("</span>");
				if (!compact) {
					sb.append("|");
				}
			}
		}
		sb.append("<br>");
		
		sb.append(Format.leftPad(String.valueOf(y), 2, "&nbsp;"));
		sb.append("&nbsp;|");
		for (int x = 0; x <= maxX; x++) {
			final XY idx = new XY(x, y);
			final ISystemDescr sd = index.get(idx);
			if (sd == null) {
				sb.append(compact ? "&nbsp;&nbsp;&nbsp;" : "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|");
			} else {
				sb.append("<span id=\"type_").append(x).append("_").append(y).append("\">");
				sb.append(formatCell(sd.getType(), compact));
				sb.append("</span>");
				if (!compact) {
					sb.append("|");
				}
			}
		}
		sb.append("<br>");
		
	}
	public static String formatCell(String text, boolean compact) {
		String s = Format.leftPad(text, compact ? 3 : 4).replace(" ", "&nbsp;");
		if (!compact) {
			s += "&nbsp;"; 
		}
		return s;
	}
	private void assignLabels(HashMap<XY, ISystemDescr> index) {
		for (final ISystemDescr systemDescr : index.values()) {
			new SystemComponent(systemDescr, content, compact);
		}
	}

}
